#pragma once

#include <windows.h>		// Header File For Windows
#include <gl\gl.h>
#include <gl\glu.h>
#include "Vector.h"
#include "Matrix.h"

enum CameraMode
{
	Inactive,
	Translate,
	Rotate,
	Zoom,
};

class Camera
{
public:
	// default constructor
	Camera();

	// constructor setting up camera orientation
	// position is position in 3D, aim is the aim coordinate in 3D, up is the up vector
	Camera(Vector3d position, Vector3d aim, Vector3d up);

	// constructor setting up camera orientation and view volume
	// position is position in 3D, aim is aim coordinate in 3D, up is up vector
	// nearPlane is nearPlane clipping plane, farPlane is farPlane clipping plane, 
	// fov is field of view angle in degrees
	Camera(Vector3d position, Vector3d aim, Vector3d up, float nearPlane, float farPlane, float fov);

	// sets the clipping planes of the view volume
	void SetClippingPlanes(float nearPlane, float farPlane);

	// sets the FOV, fov should be in degrees
	void SetFov(float fov);	
	const float GetFov(void) const;	

	// set routines for _position, _aim, and _up vector
	void SetPosition(Vector3d position);
	void SetAim(Vector3d aim);
	void SetUp(Vector3d up);

	const Vector3d GetPosition(void) const;
	const Vector3d GetAim(void) const;
	const Vector3d GetUp(void) const;

	// reset the camera to its initial position
	void Reset();

	// focus camera to some input aim position
	void SetCenterOfFocus(Vector3d newAim);

	void SetDefaults();

	// function to use the camera as the opengl camera
	// width and height are the width and height of the window
	void PerspectiveDisplayUpdate(int width, int height);
	void PerspectiveDisplayUpdate(int width, int height, float fov);
	void PerspectiveDisplay(int width, int height) const;
	void PerspectiveDisplay(int width, int height, float fov) const;

	// function that handles mouse events
	void HandleMouseEvent(UINT buttonState, int x, int y);

	// function that handles mouse movements
	void HandleMouseMotion(int x, int y);

	const Camera& operator=(const Camera& cam);

private:
	Vector3d _position;
	Vector3d _aim; 
	Vector3d _up;

	float _nearPlane;
	float _farPlane;
	float _fov;

	// all variables starting with 'Default' hold the initial camera values
	// these values are used if the camera is reset to its initial state
	Vector3d _defaultPosition;
	Vector3d _defaultAim;
	Vector3d _defaultUp;

	double _defaultAzimuth;
	double _defaultElevation;

	double _currentAzimuth;
	double _currentElevation;

	double _deltaAzimuth;
	double _deltaElevation;
	double _localDeltaAzimuth;
	double _localDeltaElevation;

	int _mouseStartX;
	int _mouseStartY;
	int _mousePrevX;
	int _mousePrevY;

	static const float _epsilon;

	GLdouble _modelViewMatrix[16];
	GLdouble _projectionMatrix[16];
	GLint _viewPort[4];

	CameraMode _mode;

	Vector3d _previousMousePosition;
	int _width;
	int _height;

	void Initialize();

	static void RotateX(Vector3d *v, double degree);
	static void RotateY(Vector3d *v, double degree);
	static void ArbitraryRotate(Vector3d up, Vector3d V, Vector3d width, double degreeX, double degreeY, Vector3d& point, Vector3d aim);
};
